
#include "string.h"
#include "../lib/data_pool_named.h"
#include "jxos_config.h"
#include "jxos_bulletin_board.h"
#include "jxos_malloc.h"
#include "jxos_registry.h"

#if (JXOS_BULLETIN_BOARD_ENABLE == 1)

static DATA_POOL_NAMED_STRUCT bulletin_board_handle_list[BULLETIN_BOARD_MAX];
static uint8_t bulletin_board_handle_list_count = 0;
JXOS_MALLOC_MEM_POOL_STRUCT bulletin_board_handle_list_mem_pool;

void jxos_bulletin_board_init(void)
{
    memset(bulletin_board_handle_list, 0, sizeof(DATA_POOL_NAMED_STRUCT)*BULLETIN_BOARD_MAX);
    bulletin_board_handle_list_mem_pool.mem_pool = (void*)bulletin_board_handle_list;
    bulletin_board_handle_list_mem_pool.len = sizeof(DATA_POOL_NAMED_STRUCT)*BULLETIN_BOARD_MAX;
    bulletin_board_handle_list_mem_pool.offset = 0;
    bulletin_board_handle_list_count = 0;
}

JXOS_BULLETIN_BOARD_HANDLE jxos_bulletin_board_create(uint8_t* space,
						uint16_t space_len,
						uint8_t data_size,
						char* bulletin_board_name)
{
    DATA_POOL_NAMED_STRUCT* h = 0;
    if(jxos_malloc_set_mem_pool(&bulletin_board_handle_list_mem_pool) == 0){
        while(1);
    }
    if((space == 0)
        ||(space_len == 0)
        ||(data_size == 0)
        ||(bulletin_board_name == 0)
    ||(space_len < data_size)
	||(data_size < 3)){
        return 0;
    }

	if(space_len/data_size > 255){
		space_len = data_size*255;	//make sure the number of bulletins is less the 255
	}

    h = jxos_malloc(sizeof(DATA_POOL_NAMED_STRUCT));
    if(h != 0){
		if(data_pool_named_init(h, space, space_len, data_size) == 1){
#if (JXOS_REGISTRY_ENABLE == 1)
            if(jxos_registry_register(bulletin_board_name, h) == 1){
#endif
                bulletin_board_handle_list_count++;
#if (JXOS_REGISTRY_ENABLE == 1)
            }
            else{
                h = 0;
            }
#endif
		}
		else{
			h = 0;
		}
    }

    return (JXOS_BULLETIN_BOARD_HANDLE)h;
}

uint8_t jxos_bulletin_board_send(JXOS_BULLETIN_BOARD_HANDLE bulletin_board, char* sender_name,
							uint8_t* data_to_send, uint8_t data_to_send_len)
{

    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(sender_name == 0)){
        return 0;
    }

	return data_pool_named_write_data((DATA_POOL_NAMED_STRUCT*)bulletin_board, sender_name, data_to_send, data_to_send_len);
}

uint8_t jxos_bulletin_board_receive(JXOS_BULLETIN_BOARD_HANDLE bulletin_board,
							uint8_t bulletin_serial_num, uint8_t* receive_buffer, uint8_t* receive_data_len)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))){
        return 0;
    }

    return data_pool_named_read_data((DATA_POOL_NAMED_STRUCT*)bulletin_board, 0, (uint16_t)bulletin_serial_num, receive_buffer, receive_data_len);
}

uint8_t jxos_bulletin_board_receive_latest(JXOS_BULLETIN_BOARD_HANDLE bulletin_board,
							uint8_t* receive_buffer, uint8_t* receive_data_len)
{
	uint16_t num;
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))){
        return 0;
    }


	num = data_pool_named_check_data_num((DATA_POOL_NAMED_STRUCT*)bulletin_board, 0, 0);
	if((num != 0)&&(num != 0xffff)){
		return data_pool_named_read_data((DATA_POOL_NAMED_STRUCT*)bulletin_board, 0, (num-1), receive_buffer ,receive_data_len);
	}
	else{
		return 0;
	}
}

uint8_t jxos_bulletin_board_check_empty(JXOS_BULLETIN_BOARD_HANDLE bulletin_board)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))){
        return 0xff;
    }

    return data_pool_named_check_empty((DATA_POOL_NAMED_STRUCT*)bulletin_board, 0, 0);
}

uint8_t jxos_bulletin_board_check_full(JXOS_BULLETIN_BOARD_HANDLE bulletin_board)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))){
        return 0xff;
    }

    return data_pool_named_check_full((DATA_POOL_NAMED_STRUCT*)bulletin_board, 0, 0);
}

uint8_t jxos_bulletin_board_check_num(JXOS_BULLETIN_BOARD_HANDLE bulletin_board)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))){
        return 0xff;
    }

    return (uint8_t)data_pool_named_check_data_num((DATA_POOL_NAMED_STRUCT*)bulletin_board, 0, 0);
}

uint8_t jxos_bulletin_board_del_earliest(JXOS_BULLETIN_BOARD_HANDLE bulletin_board,
							char* sender_name)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(sender_name == 0)){
        return 0;
    }

    return data_pool_named_del_data(bulletin_board, sender_name, sender_name);
}

uint8_t jxos_bulletin_board_clean_up(JXOS_BULLETIN_BOARD_HANDLE bulletin_board, char* sender_name)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(sender_name == 0)){
        return 0;
    }

    return data_pool_named_clr_all((DATA_POOL_NAMED_STRUCT*)bulletin_board, sender_name, sender_name);
}

uint8_t jxos_bulletin_board_sender_name_register(JXOS_BULLETIN_BOARD_HANDLE bulletin_board, char* sender_name)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(sender_name == 0)){
        return 0;
    }

	return data_pool_named_writer_name_register((DATA_POOL_NAMED_STRUCT*)bulletin_board, sender_name);
}

uint8_t jxos_bulletin_board_sender_name_cancel(JXOS_BULLETIN_BOARD_HANDLE bulletin_board, char* sender_name)
{
    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(sender_name == 0)){
        return 0;
    }

	return data_pool_named_writer_name_cancel((DATA_POOL_NAMED_STRUCT*)bulletin_board, sender_name);
}


#if (JXOS_REGISTRY_ENABLE == 1)
JXOS_BULLETIN_BOARD_HANDLE jxos_bulletin_board_get_handle(char* bulletin_board_name)
{
    if(bulletin_board_name == 0){
        return 0;
    }
    return (JXOS_BULLETIN_BOARD_HANDLE)jxos_registry_find(bulletin_board_name);
}
#endif

uint8_t jxos_bulletin_board_check_empty_all(void)
{
	uint8_t i;
	uint16_t num;
	for(i = 0; i < bulletin_board_handle_list_count; i++){
		num = data_pool_named_check_data_num(&(bulletin_board_handle_list[i]), 0, 0);
		if((num != 0xffff)&&(num != 0)){
			return 0;
		}
	}
	return 1;
}

#if (JXOS_BULLETIN_BOARD_INDEX_ENABLE == 1)
static uint8_t read_index(DATA_POOL_STRUCT* data_pool,
										uint16_t serial_num, uint8_t* index)
{
	uint8_t* p;

	p = data_pool_get_data_piont(data_pool, serial_num);
	if(p != 0){
		*index = p[(data_pool->data_size)-1];
		return 1;
	}
	else{
		return 0;
	}
}

static uint8_t write_index(DATA_POOL_STRUCT* data_pool,
										uint16_t serial_num, uint8_t index)
{
	uint8_t* p;

	p = data_pool_get_data_piont(data_pool, serial_num);
	if(p != 0){
		p[(data_pool->data_size)-1] = index;
		return 1;
	}
	else{
		return 0;
	}
}

uint8_t jxos_bulletin_board_read_index(JXOS_BULLETIN_BOARD_HANDLE bulletin_board,
										uint8_t bulletin_serial_num, uint8_t* index)
{
	DATA_POOL_STRUCT* data_pool;

    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(index == 0)){
        return 0;
    }

	data_pool = &(((DATA_POOL_NAMED_STRUCT*)bulletin_board)->data_pool);

	return read_index(data_pool, (uint16_t)bulletin_serial_num, index);
}

uint8_t jxos_bulletin_board_get_next_index(JXOS_BULLETIN_BOARD_HANDLE bulletin_board, uint8_t* local_index)
{
	DATA_POOL_STRUCT* data_pool;
	uint8_t earliest_index;
	uint8_t last_index;
	uint16_t num;

    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(local_index == 0)){
        return 0;
    }

	data_pool = &(((DATA_POOL_NAMED_STRUCT*)bulletin_board)->data_pool);

	num = data_pool_check_data_num(data_pool);
	if((num == 0)||(num == 0xffff)){
		return 0;
	}

	if(read_index(data_pool, 0, &earliest_index) == 0){
		return 0;
	}
	if(read_index(data_pool, num-1, &last_index) == 0){
		return 0;
	}

	if(earliest_index <= last_index){
		  if(((*local_index) < earliest_index)
			 ||((*local_index) > last_index)){
			   (*local_index) = earliest_index;
		  }
		  else{
		  		(*local_index) += 1;
		  }
	}
	else{
		  if(((*local_index) >= earliest_index)
			 ||((*local_index) <= last_index)){
		  		(*local_index) += 1;
		  }
		  else{
			   (*local_index) = earliest_index;
		  }
	}

	return 1;
}

uint8_t jxos_bulletin_board_send_with_index(JXOS_BULLETIN_BOARD_HANDLE bulletin_board, char* sender_name,
							uint8_t* data_to_send, uint8_t data_to_send_len)
{
	DATA_POOL_STRUCT* data_pool;
	uint8_t temp_index;
	uint16_t num;

    if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))
	   ||(sender_name == 0)){
        return 0;
    }

	data_pool = &(((DATA_POOL_NAMED_STRUCT*)bulletin_board)->data_pool);

	if(data_to_send_len > (data_pool->data_size)-2){
        return 0;
	}

	temp_index = ((DATA_POOL_NAMED_STRUCT*)bulletin_board)->write_enable;
	((DATA_POOL_NAMED_STRUCT*)bulletin_board)->write_enable = 1;
	if(data_pool_named_write_data((DATA_POOL_NAMED_STRUCT*)bulletin_board, sender_name, data_to_send, data_to_send_len)){
		num = data_pool_check_data_num(data_pool);
		if(write_index(data_pool, (num-1), (temp_index+1)) == 1){
			temp_index++;
			num = 1;
		}
		else{
			num = 0;
		}
	}
	else{
		num = 0;
	}
	((DATA_POOL_NAMED_STRUCT*)bulletin_board)->write_enable = temp_index;

	return (uint8_t)num;
}

uint8_t jxos_bulletin_board_receive_by_index(JXOS_BULLETIN_BOARD_HANDLE bulletin_board,
							uint8_t index, uint8_t* receive_buffer, uint8_t* receive_data_len)
{
	DATA_POOL_STRUCT* data_pool;
	uint8_t index_temp;
	uint16_t num;
	uint16_t i;

   if((bulletin_board == 0)
       ||(bulletin_board < (void*)(bulletin_board_handle_list_mem_pool.mem_pool))
       ||(bulletin_board > (void*)(bulletin_board_handle_list_mem_pool.mem_pool+bulletin_board_handle_list_mem_pool.offset))){
        return 0;
    }

	data_pool = &(((DATA_POOL_NAMED_STRUCT*)bulletin_board)->data_pool);

	num = data_pool_check_data_num(data_pool);
	if((num == 0)||(num == 0xffff)){
		return 0;
	}

	for(i = 0; i < num; i++){
		if(read_index(data_pool, i, &index_temp) == 1){
			if(index_temp == index){
				index_temp = data_pool_read_data(data_pool, i, receive_buffer, receive_data_len);
				break;
			}
		}
	}
	if(i >= num){
        index_temp = 0;     //not find by index
	}

	return index_temp;
}
#endif

#endif


/**************************************
//e.g.
//send
    if(jxos_bulletin_board_check_full(test_bin_h) == 1){
        jxos_bulletin_board_del_earliest(test_bin_h, "tps111");
    }
    jxos_bulletin_board_send_with_index(test_bin_h, "tps111", "test", 5);

//rec
	uint8_t last_index_temp;
	static uint8_t last_index = 0xff;

    uint8_t buff[30];
  	uint8_t len;

    if(jxos_bulletin_board_check_empty(r_bin) == 1){
		printf("empty\r\n");
        return;
	}
	last_index_temp = last_index;
	jxos_bulletin_board_get_next_index(r_bin, &last_index_temp);
	if(jxos_bulletin_board_receive_by_index(r_bin, last_index_temp, buff, &len) == 1){
		last_index = last_index_temp;
        printf("buff rec OK: %s, len %d\r\n", buff, len);
	}
	else{
		printf("no new msg\r\n");
	}

**********************************/
